package com.hclc.config.aop.joblog.aspect;

import com.hclc.config.util.PrintStackTraceUtil;
import com.hclc.entity.model.JobLogsModel;
import com.hclc.impl.job.JobLogsServiceImpl;
import com.hclc.mapper.base.JobExecuteRecordMapper;
import com.hclc.config.aop.joblog.JobLogUtil;
import com.hclc.config.context.AppContext;
import com.hclc.entity.model.JobExecuteRecordModel;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: hef
 * 任务切面
 * @Date: Create in 3:50 下午 2020/11/8
 */
@Aspect
@Component
@Slf4j
public class JobAspect {

    @Autowired
    private JobExecuteRecordMapper jobExecuteRecordMapper;

    @Autowired
    private JobLogsServiceImpl jobLogsService;

    /**
     * 定义切面
     *
     * @param
     * @return void
     * @Description: TODO(定义切面)
     * @author hef
     * @version 1.0
     * @date 2020/11/8 4:07 下午
     */
    @Pointcut("@annotation(com.hclc.config.aop.joblog.annotation.JobExecuteRecord)")
    public void annotationPointcut() {

    }

    /**
     * 进入切面之前，初始化日志列表
     *
     * @param joinPoint
     * @return void
     * @Description: TODO(进入切面之前, 初始化日志列表)
     * @author hef
     * @version 1.0
     * @date 2020/11/8 4:07 下午
     */
    @Before("annotationPointcut()")
    public void beforePointcut(JoinPoint joinPoint) {
        // 此处进入到方法前  可以实现一些业务逻辑
        List<JobLogsModel> logList = new ArrayList<>();
        AppContext.putThreadContext(JobLogUtil.JOB_LOG_KEY, logList);
    }

    /**
     * 执行结束保存任务执行记录,以及任务日志
     *
     * @param joinPoint
     * @return java.lang.Object
     * @Description: TODO(执行结束保存任务执行记录, 以及任务日志)
     * @author hef
     * @version 1.0
     * @date 2020/11/8 4:08 下午
     */
    @Around("annotationPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) {
        JobExecutionContext arg = (JobExecutionContext) joinPoint.getArgs()[0];
        JobKey key = arg.getJobDetail().getKey();
        String group = key.getGroup();
        Object result = null;
        JobExecuteRecordModel.JobExeStatusEnum jobExeStatusEnum = JobExecuteRecordModel.JobExeStatusEnum.SUCCESS;
        try {
            result = joinPoint.proceed();
        } catch (Throwable e) {
            //保存异常信息
            jobExeStatusEnum = JobExecuteRecordModel.JobExeStatusEnum.FAIL;
            JobLogUtil.saveLog("任务发生异常:{}", PrintStackTraceUtil.getTrace(e));
        }

        /** 1.保存任务执行记录 **/
        String executeRecordId = createExecuteRecord(group, jobExeStatusEnum);

        /** 2.保存任务日志 **/
        saveLog(executeRecordId, group);

        AppContext.clearThreadLocal();
        return result;
    }


    /**
     * 生成任务执行记录
     *
     * @param jobName          任务名称
     * @param jobExeStatusEnum 任务执行状态
     * @return java.lang.String
     * @Description: TODO(返回任务记录id)
     * @author hef
     * @version 1.0
     * @date 2020/11/8 4:05 下午
     */
    private String createExecuteRecord(String jobName, JobExecuteRecordModel.JobExeStatusEnum jobExeStatusEnum) {
        JobExecuteRecordModel jobExecuteRecordModel = new JobExecuteRecordModel();
        jobExecuteRecordModel.setLogDatetime(LocalDateTime.now());
        jobExecuteRecordModel.setJobExeStatus(jobExeStatusEnum);
        jobExecuteRecordModel.setJobId(jobName);

        jobExecuteRecordMapper.insert(jobExecuteRecordModel);
        return jobExecuteRecordModel.getId();
    }

    /**
     * 保存任务执行日志
     *
     * @param jobExecuteRecordId 任务执行记录id
     * @return void
     * @Description: TODO(保存任务执行日志)
     * @author hef
     * @version 1.0
     * @date 2020/11/8 4:06 下午
     */
    private void saveLog(String jobExecuteRecordId, String jobName) {
        List<JobLogsModel> logsModels = (ArrayList<JobLogsModel>) AppContext.getThreadContext(JobLogUtil.JOB_LOG_KEY);
        logsModels.stream().forEach(s -> {
            s.setJobRecordId(jobExecuteRecordId);
            s.setJobId(jobName);
        });
        jobLogsService.saveBatch(logsModels);
    }
}
